package blatt6;

import java.io.FileNotFoundException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;

public class Anwendung {

	public static void main(String args[]) {
		
		RandomAccessFile file;
		StringTokenizer st;
		String 	zeile,
				dateipfad = "", 
				method = "Interval";
		
		try {
			if (args.length == 1) {
				dateipfad = args[0];
			} else if (args.length > 1) {
				method = args[0];
				dateipfad = args[1];
			} else {
				throw new IllegalArgumentException("Zu wenig Argumente übergeben.");
			}
			
			file = new RandomAccessFile(dateipfad, "r");
			
			if (method.toLowerCase().equals("interval")) {

				Interval[] ival = new Interval[500];
				int start, ende;
				int j = 0;
				while ((zeile = file.readLine()) != null) {
					st = new StringTokenizer(zeile, ",");
					start = Integer.parseInt(st.nextToken());
					ende = Integer.parseInt(st.nextToken());
					ival[j++] = new Interval(start, ende);
				}
				Interval[] ivalsliced = new Interval[j];
				System.arraycopy(ival, 0, ivalsliced, 0, j);

				System.out.println("\nEs wurden " + j + " Zeilen mit folgendem Inhalt gelesen:");
				printIntervalArray(ivalsliced);
				
				Arrays.sort(ivalsliced);
				
				System.out.println("Sortiert: ");
				printIntervalArray(ivalsliced);
				
				// Scheduling:
				ArrayList<Interval> list = intervalScheduling(ivalsliced);
				
				// Ausgabe
				System.out.print("Berechnetes Intervallscheduling:\n[");
				for (int i = 0; i < list.size(); i++) {
					System.out.print(list.get(i).toString());
					if (i < list.size()-1) System.out.print(", ");
				}
				System.out.println("]\n");

			} else if (method.toLowerCase().equals("lateness")) {

				Job[] job = new Job[500];
				int duration, deadline;
				int j = 0;
				while ((zeile = file.readLine()) != null) {
					st = new StringTokenizer(zeile, ",");
					duration = Integer.parseInt(st.nextToken());
					deadline = Integer.parseInt(st.nextToken());
					job[j++] = new Job(duration, deadline);
				}
				Job[] jobsliced = new Job[j];
				System.arraycopy(job, 0, jobsliced, 0, j);

				System.out.println("\nEs wurden " + j + " Zeilen mit folgendem Inhalt gelesen:");
				printIntervalArray(jobsliced);
				
				Arrays.sort(jobsliced);
					
				System.out.println("Sortiert:");
				printIntervalArray(jobsliced);

				int[] list = latenessScheduling(jobsliced);
				
				// Ausgabe
				System.out.println("Berechnetes Latenessscheduling:");
				printIntArray(list);

				System.out.println("Berechnete maximale Verspätung: " + getMaxLateness(jobsliced));
			} else {
				throw new Exception("Nur die Methoden 'Interval' und 'Lateness' sind gültig.");
			}
		} catch (ClassCastException e) {
			System.out.println("No Comparable Implementation Fehler.");
		} catch (SecurityException e) {
			System.out.println("Kein Zugriffsrecht auf übergebene Datei.");
		} catch (FileNotFoundException e) {
			System.out.println("Die Übergebene Datei konnte nicht gefunden werden. \n" + e.getMessage());
		} catch (NumberFormatException e) {
			System.out.println("Eine ungültige Zahl wurde übergeben, oder stand in der übergebenen Datei.");
		} catch (IllegalArgumentException e) {
			System.out.println("Falsche Argumente: " + e.getMessage());
		} catch (IndexOutOfBoundsException e) {
			System.out.println("Da lief ein Index raus: " + e.getMessage());
		} catch (NoSuchElementException e) {
			System.out.println("Die einzulesene Datei ist fehlerhaft. Eventuell enthält eine Zeile nicht genau zwei Token.");
		} catch (ArrayStoreException e) {
			System.out.println("Interner Verarbeitungsfehler: Eine Element konnte nicht ins andere Array kopiert werden, da unterschiedliche Typen verwendet wurden. " + e.getMessage());
		} catch (Exception e) {
			System.out.println("Fehler: " + e.getMessage());
		}

	}

	public static void printIntervalArray(Object[] array) {
		System.out.print("[");
		for (int i = 0; i < array.length; i++) {
			System.out.print(array[i].toString());
			if (i < array.length - 1)
				System.out.print(", ");
		}
		System.out.println("]\n");
	}

	public static void printIntArray(int[] list) {
		System.out.print("[");
		for (int i = 0; i < list.length; i++) {
			System.out.print(list[i]);
			if (i != (list.length - 1))
				System.out.print(", ");
		}
		System.out.println("]\n");
	}

	public static int getMaxLateness(Job[] jobs) {
		int now = 0;
		int maxLateness = 0, tmpLateness = 0;
		for (int i = 0; i < jobs.length; i++) { // Invariante: Nach jedem
												// Schleifendurchlauf gilt, dass
												// maxLateness die maximale
												// Verspätung beinhaltet
			now += jobs[i].getDuration();
			tmpLateness = now - jobs[i].getDeadline();
			if (maxLateness < tmpLateness)
				maxLateness = tmpLateness;
		}
		return maxLateness;
	}

	public static ArrayList<Interval> intervalScheduling(Interval[] array) {
		ArrayList<Interval> list = new ArrayList<Interval>();
		int now = 0;
		for (int i = 0; i < array.length; i++) { // Invariante: Nach jedem
													// Schleifendurchlauf gilt,
													// dass die Liste alle
													// Elemente beinhaltet, bei
													// denen der vorige Endwert
													// kleiner/gleich dem neuen
													// Startwert ist
			if (now <= array[i].getStart()) {
				list.add(array[i]);
				now = array[i].getEnd();
			}
		}
		return list;
	}

	public static int[] latenessScheduling(Job[] array) {
		int[] list = new int[array.length];
		int now = 0;
		for (int i = 0; i < array.length; i++) { // Invariante: Nach jedem
													// Schleifendurchlauf gilt,
													// dass now die Summe aller
													// Laufzeiten ist
			list[i] = now;
			now += array[i].getDuration();
		}
		return list;
	}
	
}
